import gtk
from widgetOrganizer import WidgetOrganizer
from gobject import idle_add
from time import sleep

class Find(WidgetOrganizer, gtk.HBox):
    def __init__(self, ancestor):
        gtk.HBox.__init__(self)
        WidgetOrganizer.__init__(self, 'Find', ancestor)
        self.hide()
        
        self.starting_point = None
        self.input = None
        self.tag = None
        self.key = ''
        
        self._createCloseButton()
        self._createEntry()
        self._createNavigation()
        
    def _createCloseButton(self):
        closeButton = gtk.Button('<span foreground="#ffffff" weight="bold"> x </span>')
        closeButton.show()
        closeButton.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffb7b7'))
        closeButton.get_children()[0].set_use_markup(True)
        def enter(closeButton, *args):
            closeButton.get_children()[0].set_markup('<span foreground="#ffb7b7" weight="bold"> x </span>')
            return True
        def leave(closeButton, *args):
            closeButton.get_children()[0].set_markup('<span foreground="#ffffff" weight="bold"> x </span>')
        def clicked(closeButton, *args):
            self.clear_mark()
            self.hide()
        closeButton.connect('enter', enter)
        closeButton.connect('leave', leave)
        closeButton.connect('clicked', clicked)
        self.pack_start(closeButton, expand=False)
        
    def _createEntry(self):
        self.entry = gtk.Entry()
        self.entry.show()
        self.pack_start(self.entry, expand=False)
        self.entry.connect('event-after', self._event_update)
        
    def _createNavigation(self):
        def clicked(nextButton, forward):
            if self.input and self.input.getAncestor('Notebook').cursor_moved:
                self.clear_mark()
                self.input = None
                self.iters = (None, None)
            if forward:
                self.search(self.input, self.iters[1], forward=forward)
            else:
                self.search(self.input, self.iters[0], forward=forward)
        nextButton = gtk.Button('Next')
        nextButton.show()
        nextButton.connect('clicked', clicked, True)
        self.pack_start(nextButton, expand=False)
        previousButton = gtk.Button('Previous')
        previousButton.show()
        previousButton.connect('clicked', clicked, False)
        self.pack_start(previousButton, expand=False)
    
    def _event_update(self, entry, *args):
        if self.key == entry.get_text():
            return
        self.key = entry.get_text()
        self.search()
    
    def mark_hit(self, forward=True):
        self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
        self.tag = self.input.buffer.create_tag()
        self.tag.set_property('background-gdk', gtk.gdk.color_parse('#d0d0d0'))
        self.input.buffer.apply_tag(self.tag, self.iters[0], self.iters[1])
        self.input.placeCursor(self.iters[0], focus=False)
    
    def clear_mark(self):
        if self.input:
            self.input.buffer.remove_tag(self.tag, *self.input.buffer.get_bounds())
    
    def search(self, input=None, start_iter=None, forward=True):
        self.clear_mark()
        
        #get starting point
        if input:
            if start_iter:
                pass
            else:
                start_iter = input.buffer.get_start_iter()
        else:    
            if start_iter:
                raise 'start_iter without apropriate input is useless'
            else:
                input, start_iter = self.find_start_point()
        self.starting_point = (input, start_iter)
        
        #search through all inputs
        if forward:
            comparison = -1
        else:
            comparison = 1
        
        passed = False
        while True:
            #break loop when come to the starting point the second time
            if input is self.starting_point[0] and self.starting_point[1].compare(start_iter)>comparison:
                if passed:
                    break
                else:
                    passed=True
            
            #get search area
            searchArea, nextSearch = input.get_search_area(start_iter, forward)
                
            #search the input in search_area
            result = self._search_string(searchArea, forward)
            if result:
                self.store_last_hit(input, result)
                self.mark_hit()
                return
            else:
                input, start_iter = nextSearch
        
        #first input is searched again, since it was only searched from start_iter forwards
        result = self._search_string(input.get_search_area(start_iter, forward)[0], forward)
        if result:
            self.store_last_hit(input, result)
            self.mark_hit()
            return
        
        #if nothing is found, entry is marked red
        self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffb7b7'))
        
    def _search_string(self, searchArea, forward):
        start_iter, end_iter = searchArea
        
        if forward:
            result = start_iter.forward_search(self.key, gtk.TEXT_SEARCH_TEXT_ONLY, end_iter)
        else:
            result = start_iter.backward_search(self.key, gtk.TEXT_SEARCH_TEXT_ONLY, end_iter)
            
        if result:
            return result
        else:
            return None
    
    def store_last_hit(self, input, data):
        self.input = input
        self.input.getAncestor('Notebook').cursor_moved = False
        self.iters = data
    
    def find_start_point(self):
        notebook = self.getAncestor('MainWindow').getChildren('Notebook')
        sheet = notebook.activeInput.getAncestor('Worksheet')
        if not sheet:
            sheet = notebook.activeInput.getAncestor('Pythonsheet')
        if notebook.get_current_sheet() is sheet:
            buffer = notebook.activeInput.buffer
            iter = buffer.get_iter_at_mark(buffer.get_insert())
            return notebook.activeInput, iter
        else:
            input = notebook.get_current_sheet().getChildren('Input')
            if input:
                iter = input.buffer.get_start_iter()
            else:
                iter = None
            return input, iter 
    